package repo

import (
	"errors"
	uuid "github.com/satori/go.uuid"
	"strings"
	"sync"
	"time"
)

var mutex sync.RWMutex

type DeviceWithState struct {
	cacheDevice
	Online            bool
	LastHeartbeatTime time.Time
}

func GetAll() []*DeviceWithState {
	caches := getAllCache()
	result := make([]*DeviceWithState, 0)
	for _, cache := range caches {
		result = append(result, &DeviceWithState{
			cacheDevice:       *cache,
			Online:            cache.online,
			LastHeartbeatTime: cache.lastHeartbeatTime,
		})
	}
	return result
}

// 通过主键ID来获取设备
func GetDeviceByPrimaryId(id string) (*Dev, bool, error) {
	var count int64
	err := db.Model(Dev{}).Where(Dev{ID: id}).Count(&count).Error
	if err != nil {
		return nil, false, err
	}
	if count == 0 {
		return nil, false, nil
	}

	dev := &Dev{ID: id}
	err = db.First(dev).Error
	if err != nil {
		return nil, false, err
	}
	return dev, true, nil
}

// 通过设备唯一标识符获取设备，主要供设备心跳回调来使用
func GetDeviceByFactoryIdentity(deviceId string) (*Dev, bool) {
	mutex.RLock()
	defer mutex.RUnlock()

	cacheDev, ok := getCache(deviceId)
	if ok {
		return &cacheDev.Dev, true
	}
	return nil, false
}

// 手动添加设备
func CreateStaticDevice(param *StaticDeviceParam) error {
	if param.Model == "" || param.IP == "" {
		return errors.New("参数不全")
	}

	var count int64
	err := db.Where("ip=?", param.IP).Count(&count).Error
	if err != nil {
		return err
	}
	if count != 0 {
		return errors.New("已存在相同ip的设备")
	}

	id := simpleUUID()
	dev := &Dev{
		ID:        id,
		DeviceId:  id,
		Model:     param.Model,
		IP:        param.IP,
		Context:   param.Context,
		IsDynamic: false,
	}

	mutex.Lock()
	defer mutex.Unlock()

	err = db.Create(dev).Error
	if err != nil {
		return err
	}

	upsertCache(*dev)
	return nil
}

// 动态添加设备
func CreateDynamicDevice(param *DynamicDeviceParam) error {
	if param.Model == "" || param.IP == "" || param.DeviceId == "" {
		return errors.New("参数不全")
	}

	////如果在创建动态设备前，已经有了静态设备，那么就更新设备信息
	//staticDev := new(Dev)
	//err := db.Where("ip=?", param.IP).Find(staticDev).Error
	//if err != nil {
	//	return nil
	//}
	//if staticDev.ID != "" {
	//	staticDev.IsDynamic = true
	//	staticDev.DeviceId = param.DeviceId
	//	return db.Save(staticDev).Error
	//}

	id := simpleUUID()
	dev := &Dev{
		ID:        id,
		DeviceId:  param.DeviceId,
		Model:     param.Model,
		IP:        param.IP,
		Context:   param.Context,
		IsDynamic: true,
	}

	mutex.Lock()
	defer mutex.Unlock()

	err := db.Create(dev).Error
	if err != nil {
		return err
	}

	upsertCache(*dev)
	return nil
}

// 供用户更新静态设备信息
func UpdateStaticDevice(param *Dev) error {
	if param.ID == "" {
		return errors.New("参数不全")
	}

	mutex.Lock()
	defer mutex.Unlock()

	dev, exist, err := GetDeviceByPrimaryId(param.ID)
	if err != nil {
		return err
	}
	if !exist {
		return errors.New("没有找到设备")
	}
	if dev.IsDynamic {
		return errors.New("不支持修改动态发现的设备信息")
	}

	dev.Context = param.Context
	dev.IP = param.IP
	dev.Model = param.Model
	err = db.Updates(dev).Error
	if err != nil {
		return err
	}

	upsertCache(*dev)
	return nil
}

// 供回调函数更新动态设备信息（或静态转动态）
func UpdateDynamicDevice(deviceId string, ip string) error {
	dev, _ := GetDeviceByFactoryIdentity(deviceId)
	dev.IP = ip
	dev.IsDynamic = true
	return db.Updates(dev).Error
}

// 更新设备心跳时间
func HeartbeatDevice(deviceId string) {
	d, ok := cacheMap[deviceId]
	if ok {
		d.lastHeartbeatTime = time.Now()
	}
}

// 使用主键id删除设备
func DeleteDevice(id string) error {
	mutex.Lock()
	defer mutex.Unlock()

	var count int64
	err := db.Model(Dev{}).Where(Dev{ID: id}).Count(&count).Error
	if err != nil {
		return err
	}
	if count == 0 {
		return nil
	}

	dev := &Dev{ID: id}
	err = db.First(dev).Error
	if err != nil {
		return err
	}

	err = db.Delete(dev).Error
	if err != nil {
		return err
	}

	rmCache(dev.DeviceId)
	return nil
}

func simpleUUID() string {
	return strings.ReplaceAll(uuid.NewV4().String(), "-", "")
}
